/* 
对于昂贵的函数调用，执行复杂计算的函数
对于具有有限且高度重复输入范围的函数
对于具有重复输入值的递归函数
对于纯函数，即每次使用特定输入调用时返回相同输出的函数
*/
function main() {
  /* 用于缓存函数的高阶函数 */
  const memoize = function (func, thisArg) {
    // 做一个缓存对象：入参整体作为Key 计算结果作为值
    // 创建一个没有原型的对象实例
    let cache = Object.create(null);

    // 相当于new Object() 实例的原型是夏娃（Object.prototype）
    // 所有实例拥有很多不必要的方法 toString hasOwnProperty ...
    // let cache = {};

    // 如果需要绑定特殊的this
    thisArg = thisArg || this;

    /* 丢还一个新函数 */
    return (...key) => {
      // 当缓存中没有结果时 直接调用func函数计算结果并丢入缓存
      if (!cache[key]) {
        console.log("首次计算结果");
        cache[key] = func.apply(thisArg, key);
      } else {
        console.log("使用缓存");
      }

      // console.log("cache before return", cache);

      // 从缓存中读取值
      return cache[key];
    };
  };

  const add = (a, b) => a + b;
  const madd = memoize(add); // 函数缓存

  console.log(madd(10, 20)); // 30
  console.log(madd(10, 20)); // 30
}
// main();

/* 额外练习 */
function main02() {
  /* add函数进去 */
  const memoize = (fn) => {
    /* 闭包存储内层函数的缓存介质 入参为Key 结果为值*/
    const cacheObj = {};

    /* 自带缓存的madd函数出来 */
    return function (...args) {
      /* 缓存中没有结果则执行运算 */
      if (!cacheObj[args]) {
        // 调用原始函数求计算结果并返回
        const ret = fn.apply(null, args);
        console.log("缓存中无结果 执行昂贵运算");

        // 只要曾经运算过 就缓存其结果
        cacheObj[args] = ret;
      }

      // 返回缓存中的结果
      return cacheObj[args];
    };
  };

  const add = (a, b) => a + b;
  const madd = memoize(add);

  console.log(madd(12, 34));
  console.log(madd(12, 34));
}
main02();
